///////////////////////////////////////////////////////////////////////
//  Siglaz.Util
///////////////////////////////////////////////////////////////////////
Siglaz.Util = {
	serialize: function(obj){
		var t = typeof(obj);
		if (t != "object" || obj === null) {
			// simple data type	
			if (t == "string") 
				obj = '"' + obj + '"';
			return String(obj);
		}
		else {
			// recurse array or object
			var n, v, json = [], arr = (obj && obj.constructor == Array);
			for (n in obj) {
				t = typeof(obj[n]);
				if (t == "function") 
					continue;
				v = obj[n];
				if (t == "string") 
					v = '"' + v + '"';
				else 
					if (t == "object" && v !== null) 
						v = this.serialize(v);
				json.push((arr ? "" : '"' + n + '":') + String(v));
			}
			return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
		}
	},
	factoryObject: function(obj){
		switch (obj._objectType) {
	      case "Circle":
	          return new Siglaz.Circle(obj._attrs, obj._options);
	      case "Line":
	          return new Siglaz.Line(obj._attrs, obj._options);
	      case "Image":
	          return new Siglaz.Image(obj._attrs, obj._options);
	      case "Polygon":
	          return new Siglaz.Polygon(obj._attrs, obj._options);
	      case "Rectangle":
	          return new Siglaz.Rectangle(obj._attrs, obj._options);
	      default:
	          break;  
	    }
	},
	deserialize: function(json){
		var obj = this.parseJsonToObject(json);
		var shapes = [];
		for(var i in obj)
		{
			shapes.push(this.factoryObject(obj[i]));
		}
		return shapes;
	},
	parseJsonToObject: function(str){
	    if (str === "") 
	        str = '""';
	    eval("var p=" + str + ";");
	    return p;
	},
	isOnLine: function(p1, p2, x, y, lineWidth){
		var d = this.distancePoint2SegLine(x, y, p1.x, p1.y, p2.x, p2.y);
		return (d*2 <= lineWidth);	
	},
	distancePoint2SegLine: function(x0, y0, x1, y1, x2, y2) {
		var l2 = this.squareDistance2Pts(x1, y1, x2, y2);
		if (l2 == 0)
			return this.distance2Pts(x0, y0, x1, y1);
		var t = ((x0-x1)*(x2-x1) + (y0-y1)*(y2-y1)) / l2;
		if (t < 0)
			return this.distance2Pts(x0, y0, x1, y1);
		if (t > 1)
			return 	this.distance2Pts(x0, y0, x2, y2);
		var x = x1 + t*(x2 - x1); // x-projection
		var y = y1 + t*(y2 - y1); // y-projection
		return this.distance2Pts(x, y, x0, y0);
	},
	squareDistance2Pts: function(x1, y1, x2, y2) {
		return ((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
	},
	distance2Pts: function(x1, y1, x2, y2) {
		return Math.sqrt(this.squareDistance2Pts(x1, y1, x2, y2));
	},
	
	transformPoint: function(m, x, y) {
		//var px = x;
		//var py = y;
		var ax = x * m[0] + y * m[2] + m[4];
		var ay = x * m[1] + y * m[3] + m[5];
		return {x: ax, y: ay};
	},
	
	transformPoints: function(m, ax, ay) {
		var px = 0;
		var py = 0;
		var length = Math.min(ax.length, ay.length);
		var tpts = [];
		for (var i=0; i<length; i++) {
			px = ax[i]; py = ay[i];
			x = px * m[0] + py * m[2] + m[4];
			y = px * m[1] + py * m[3] + m[5];
			tpts.push({x: x, y: y});
		}
		return tpts;
	},
	
	transformArrayPoints: function(m, pts) {
		var px = 0;
		var py = 0;
		var length = pts.length;
		var tpts = [];
		for (var i=0; i<length; i++) {
			px = pts[i].x;
			py = pts[i].y;
			x = px * m[0] + py * m[2] + m[4];
			y = px * m[1] + py * m[3] + m[5];
			tpts.push({x: x, y: y});
		}
		return tpts;
	},
	
	invertMatrix: function(m) {
		if(m == null)
			return null
		var d = 1 / (m[0] * m[3] - m[1] * m[2]);
		var m0 = m[3] * d;
		var m1 = -m[1] * d;
		var m2 = -m[2] * d;
		var m3 = m[0] * d;
		var m4 = d * (m[2] * m[5] - m[3] * m[4]);
		var m5 = d * (m[1] * m[4] - m[0] * m[5]);
		
		return [m0, m1, m2, m3, m4, m5];
	},
	
	calculateSeatPosition: function(p1, p2, n, r){
		if(n == 0)
			return [];
		if(r == undefined)
			r = 5;
		var d = this.distance2Pts(p1.x, p1.y, p2.x, p2.y);
		var m = n*(2*r);
		if(d - m < 0)
			return this.calculateSeatPosition(p1, p2, n, r-1);
		else
		{
			var e = (d-m) / (n-1);
			var t = e + 2*r;
			var ps = [];
			var p = this.getPointInLineWithDistance(p1, p2, d, r);
			ps.push(p);
			for(var i = 1; i < n; i++)
			{
				p = this.getPointInLineWithDistance(p1, p2, d, r+t*i);
				ps.push(p);
			}
			return ps;
		}
	},
	getPointInLineWithDistance: function(p1, p2, d, di){
		var dx = p2.x - p1.x,
			dy = p2.y - p1.y,
			t = di/d;
		var x = p1.x + dx*t,
			y = p1.y + dy*t;
		return {x: x, y: y};
	}
}
